﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
using lo = sqCore.sqLogger;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Driver.Builders;


namespace sqCore
{
    /* Docs:
     * Summary
        * Mongo query Job object for SqlA Tasks.
     * Override Variables
        * IsDone - If false, this job not runed.
        * ExecuteTime - Time that the job executed.
        * Result - The results of the execute.
     * Variables
        * DB - SqlA db object.
        * Collection - The "table" in the DB.
        * CollectionName - Collection name --> Collection.
        * QueryDocs - The query.
        * ObjectDocs - The object in the db you want to insert/change.
        * CommandType - Insert/Change/Remove.
     */
    public class sqMongoNonQueryJob : sqJob
    {
        public sqDB DB { get; set; }
        public string CollectionName { get; set; }        
        public MongoCollection<BsonDocument> Collection { get; set; }
        public QueryDocument QueryDocs { get; set; }
        public object ObjectDocs { get; set; }        
        public sqHelpper.MongoCommand CommandType { get; set; }

        /* Docs:
        * Summary: Initialize the job.
        */
        public sqMongoNonQueryJob(sqDB DB, sqHelpper.MongoCommand CommandType = sqHelpper.MongoCommand.update, string CollectionName = default(string), QueryDocument QueryDocs = default(QueryDocument), object ObjectDocs = default(object), DateTime? QueryTime = null)
            : base()
        {
            if (QueryTime == null)
                this.ExecuteTime = DateTime.Now;
            this.CommandType = CommandType;
            this.DB = DB;
            this.CollectionName = CollectionName;
            MongoDatabase conn = this.DB.makeMongoConnection();            
            this.Collection = conn.GetCollection<BsonDocument>(this.CollectionName);            
            this.QueryDocs = QueryDocs;
            if (this.QueryDocs == null)
                this.QueryDocs = new QueryDocument();
            this.ObjectDocs = ObjectDocs;
            if (this.ObjectDocs == null)
                this.ObjectDocs = "";
            this.Result = false;            
            this.IsDone = false;            
        }

        /* Docs:
        * Summary: Initialize the job.
        */ 
        public sqMongoNonQueryJob(MongoCollection<BsonDocument> Collection, sqHelpper.MongoCommand CommandType = sqHelpper.MongoCommand.update, QueryDocument QueryDocs = default(QueryDocument), object ObjectDocs = default(object), DateTime? QueryTime = null)
            : base()
        {
            if (QueryTime == null)
                this.ExecuteTime = DateTime.Now;
            this.CommandType = CommandType;
            this.Collection = Collection;
            this.QueryDocs = QueryDocs;
            if (this.QueryDocs == null)
                this.QueryDocs = new QueryDocument();
            this.ObjectDocs = ObjectDocs;
            if (this.ObjectDocs == null)
                this.ObjectDocs = "";
            this.Result = false;
            this.IsDone = false;                                    
        }

        /* Docs:
        *Summary: Pick the currect command.
        * Variables:            
            * T - the type of the object you want to manipulate.            
        */
        public void executeJob<T>()
        {
            lo.writeLog("Start executeJob", debugOnly: true, Param:this.QueryDocs.ToJson());
            if (CommandType == sqHelpper.MongoCommand.insert)
                this.executeInsertJob<T>();
            if (CommandType == sqHelpper.MongoCommand.update)
                this.executeUpdateJob<T>();
            if (CommandType == sqHelpper.MongoCommand.remove)
                this.executeRemoveJob();
        }


        /* Docs:
        *Summary: Insert object to collection.
        * Variables:            
            * T - the type of the object you want to insert.            
        */
        private void executeInsertJob<T>()
        {
            lo.writeLog("Start insert", debugOnly: true);
            Collection.Insert<T>((T)ObjectDocs);
            this.Result = true;
        }

        /* Docs:
        *Summary: Change all object returns from the query to another object.
        * Variables:            
            * T - the type of the object you want to change.
        */
        private void executeUpdateJob<T>()
        {
            lo.writeLog("Start update", debugOnly: true);
            Collection.Update(QueryDocs, new UpdateDocument(){((T)ObjectDocs).ToBsonDocument<T>()});
            this.Result = true;            
        }

        /* Docs:
        *Summary: Remove all object returns from the query.
        */
        private void executeRemoveJob()
        {
            lo.writeLog("Start remove", debugOnly: true);
            Collection.Remove(QueryDocs);
            this.Result = true;
        }

        /* Docs:
        *Summary: Return job results.
        */
        public override object getResult()
        {
            return this.Result;
        }

        /* Docs:
        *Summary: Return new instance that similar to this job befor execute.
        */
        public override sqJob renew()
        {
            return new sqMongoNonQueryJob(this.Collection, QueryDocs: this.QueryDocs, ObjectDocs: this.ExecuteTime);
        }

        /* Docs:
        *Summary: Return new instance that equles to this job before/after execute.
        */
        public override sqJob copy()
        {
            sqMongoNonQueryJob jobC = new sqMongoNonQueryJob(this.Collection, QueryDocs: this.QueryDocs, ObjectDocs: this.ExecuteTime);
            jobC.IsDone = this.IsDone;
            jobC.Result = this.Result;
            return jobC;
        }
    }
}
